home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / hop.c < prev    next >
C/C++ Source or Header  |  1991-03-26  |  11KB  |  421 lines

  1. /*
  2.  *    HOP.C   -- trace route packets take to a remote host
  3.  *
  4.  *    02-90    -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *           UC Davis, Computing Services
  6.  *           Davis, CA
  7.  *    04-90    -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  *    08-90    -- Modified by Bill Simpson to display domain names
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include "global.h"
  14. #include "mbuf.h"
  15. #include "usock.h"
  16. #include "socket.h"
  17. #include "session.h"
  18. #include "timer.h"
  19. #include "proc.h"
  20. #include "netuser.h"
  21. #include "domain.h"
  22. #include "commands.h"
  23. #include "tty.h"
  24. #include "cmdparse.h"
  25. #include "ip.h"
  26. #include "icmp.h"
  27. #include "udp.h"
  28. #include "hardware.h"
  29.  
  30. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  31. static int16 Hoprport = 32768+666;    /* funny port for udp probes */
  32. #define HOP_HIGHBIT    32768        /* Mask to check ICMP msgs */
  33.  
  34.  
  35. #define HOPTRACE    1        /* Enable HOP tracing */
  36. #ifdef HOPTRACE
  37. static int Hoptrace = 0;
  38. static int hoptrace __ARGS((int argc,char *argv[],void *p));
  39. #endif
  40.  
  41.  
  42. static unsigned  short Hopmaxttl  = 30;        /* max attempts */
  43. static unsigned  short Hopmaxwait = 5;        /* secs timeout each attempt */
  44. static unsigned  short Hopquery   = 3;        /* #probes each attempt */
  45.  
  46. static int hopcheck __ARGS((int argc,char *argv[],void *p));
  47. static int hopttl __ARGS((int argc,char *argv[],void *p));
  48. static int hopwait __ARGS((int argc,char *argv[],void *p));
  49. static int hopnum __ARGS((int argc,char *argv[],void *p));
  50. static int geticmp __ARGS((int s,int16 lport,int16 fport,
  51.     int32 *sender,char *type,char *code));
  52.  
  53. static struct cmds Hopcmds[] = {
  54.     "check",    hopcheck,    2048,    2,    "check <host>",
  55.     "maxttl",    hopttl,        0,    0,    NULLCHAR,
  56.     "maxwait",    hopwait,    0,    0,    NULLCHAR,
  57.     "queries",    hopnum,        0,    0,    NULLCHAR,
  58. #ifdef HOPTRACE
  59.     "trace",    hoptrace,    0,    0,    NULLCHAR,
  60. #endif
  61.     NULLCHAR,
  62. };
  63.  
  64.  
  65. /* attempt to trace route to a remote host */
  66. int
  67. dohop(argc,argv,p)
  68. int argc;
  69. char *argv[];
  70. void *p;
  71. {
  72.     return subcmd(Hopcmds,argc,argv,p);
  73. }
  74.  
  75.  
  76. /* Set/show # queries sent each TTL value */
  77. static int
  78. hopnum(argc,argv,p)
  79. int argc;
  80. char *argv[];
  81. void *p;
  82. {
  83.     int16 r;
  84.     int16 x = Hopquery;
  85.     r = setshort(&x,"# queries each attempt",argc,argv);
  86.     if ((x <= 0)||(x > HOPMAXQUERY)) {
  87.         printf("Must be  0 < x <= %d\n",HOPMAXQUERY);
  88.         return 0;
  89.     } else {
  90.         Hopquery = x;
  91.     }
  92.     return (int)r;
  93. }
  94. #ifdef HOPTRACE
  95. /* Set/show tracelevel */
  96. static int
  97. hoptrace(argc,argv,p)
  98. int argc;
  99. char *argv[];
  100. void *p;
  101. {
  102.     return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  103. }
  104. #endif
  105. /* Set/show maximum TTL value for a traceroute query */
  106. static int
  107. hopttl(argc,argv,p)
  108. int argc;
  109. char *argv[];
  110. void *p;
  111. {
  112.     int16 r;
  113.     int16 x = Hopmaxttl;
  114.     r = setshort(&x,"Max attempts to reach host",argc,argv);
  115.     if ((x <= 0)||(x > 255)) {
  116.         printf("Must be  0 < x <= 255\n");
  117.         return 0;
  118.     } else {
  119.         Hopmaxttl = x;
  120.     }
  121.     return (int)r;
  122. }
  123. /* Set/show #secs until timeout for a traceroute query */
  124. static int
  125. hopwait(argc,argv,p)
  126. int argc;
  127. char *argv[];
  128. void *p;
  129. {
  130.     int16 r;
  131.     int16 x = Hopmaxwait;
  132.     r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  133.     if (x <= 0) {
  134.         printf("Must be >= 0\n");
  135.         return 0;
  136.     } else {
  137.         Hopmaxwait = x;
  138.     }
  139.     return (int)r;
  140. }
  141.  
  142. /* send probes to trace route of a remote host */
  143. static int
  144. hopcheck(argc,argv,p)
  145. int argc;
  146. char *argv[];
  147. void *p;
  148. {
  149.     struct session *sp;        /* Session for trace output */
  150.     int s;                /* Socket for queries */
  151.     int s1;                /* Raw socket for replies */
  152.     struct socket lsocket;        /* Local socket sending queries */
  153.     struct socket rsocket;        /* Final destination of queries */
  154.     int32 cticks;            /* Timer for query replies */
  155.     int32 icsource;            /* Sender of last ICMP reply */
  156.     char ictype;            /* ICMP type last ICMP reply */
  157.     char iccode;            /* ICMP code last ICMP reply */
  158.     int32 lastaddr;            /* Sender of previous ICMP reply */
  159.     struct sockaddr_in sock;
  160.     register struct usock *usp;
  161.     register struct sockaddr_in *sinp;
  162.     unsigned char sndttl, q;
  163.     int tracedone = 0;
  164.     int ilookup = 1;        /* Control of inverse domain lookup */
  165.     int c;
  166.     extern int optind;
  167.     char *hostname;
  168.     char *sname;            /* Used in resolve_a() call */
  169.     int trans;            /* Save IP address translation state */
  170.  
  171.     optind = 1;
  172.     while((c = getopt(argc,argv,"n")) != EOF){
  173.         switch(c){
  174.         case 'n':
  175.             ilookup = 0;
  176.             break;
  177.         }
  178.     }
  179.     hostname = argv[optind];
  180.     /* Allocate a session descriptor */
  181.     if((sp = newsession(hostname,HOP,0)) == NULLSESSION){
  182.         tprintf("Too many sessions\n");
  183.         keywait(NULLCHAR,1);
  184.         return 1;
  185.     }
  186.     sp->s = s = -1;
  187.     sp->flowmode = 1;
  188.  
  189.     /* Setup UDP socket to remote host */
  190.     sock.sin_family = AF_INET;
  191.     sock.sin_port = Hoprport;
  192.     tprintf("Resolving %s... ",hostname);
  193.     if((sock.sin_addr.s_addr = resolve(hostname)) == 0){
  194.         tprintf("Host %s unknown\n",hostname);
  195.         keywait(NULLCHAR,1);
  196.         freesession(sp);
  197.         return 1;
  198.     }
  199.  
  200.     /* Open socket to remote host */
  201.     tprintf("traceroute to %s\n",psocket((struct sockaddr *)&sock));
  202.     if((sp->s = s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  203.         tprintf("Can't create udp socket\n");
  204.         keywait(NULLCHAR,1);
  205.         freesession(sp);
  206.         return 1;
  207.     }
  208.     if(connect(s,(char *)&sock,sizeof(sock)) == -1){
  209.         tprintf("Connect failed\n");
  210.         keywait(NULLCHAR,1);
  211.         freesession(sp);
  212.         return 1;
  213.     }
  214.     if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  215.         tprintf("Can't create raw socket\n");
  216.         keywait(NULLCHAR,1);
  217.         freesession(sp);
  218.         return 1;
  219.     }
  220.     /* Setup structures to send queries */
  221.     /* Retrieve socket details for user socket control block */
  222.     usp = itop(s);
  223.     sinp = (struct sockaddr_in *)usp->name;
  224.     lsocket.address = sinp->sin_addr.s_addr;
  225.     lsocket.port = sinp->sin_port;
  226.     sinp = (struct sockaddr_in *)usp->peername;
  227.     rsocket.address = sinp->sin_addr.s_addr;
  228.  
  229.     /* Send queries with increasing TTL; start with TTL=1 */
  230.     if (Hoptrace)
  231.         log(sp->s,"HOPCHECK start trace to %s\n",sp->name);
  232.     for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  233.         /* Increment funny UDP port number each round */
  234.         rsocket.port = sinp->sin_port;
  235.         tprintf("%3d:",sndttl);
  236.         lastaddr = (int32)0;
  237.         /* Send a round of queries */
  238.         for (q=0; (q < Hopquery); ++q) {
  239.             send_udp(&lsocket,&rsocket,0,sndttl,NULLBUF,0,0,0);
  240.             cticks = msclock();
  241.             alarm((long)Hopmaxwait*1000L);
  242.  
  243.             /* Wait for a reply to our query */
  244.             if(geticmp(s1,lsocket.port,rsocket.port,
  245.              &icsource,&ictype,&iccode) == -1){
  246.                 if(errno != EALARM){
  247.                     alarm((long)0);    /* cancel alarm */
  248.                     goto done;    /* User reset */
  249.                 }
  250.                 /* Alarm rang, give up waiting for replies */
  251.                 tprintf(" ***");
  252.                 continue;
  253.             }
  254.             /* Save #ticks taken for reply */
  255.             cticks = msclock() - cticks;
  256.             /* Report ICMP reply */
  257.             if (icsource != lastaddr) {
  258.                 struct rr *save_rrlp, *rrlp;
  259.  
  260.                 if(lastaddr != (int32)0)
  261.                     tprintf("\n    ");
  262.             /* Save IP address translation state */
  263.                 trans = DTranslate;
  264.             /* Force output to be numeric IP addr */
  265.                 DTranslate = 0;
  266.                 tprintf(" %-15s",inet_ntoa(icsource));
  267.             /* Restore original state */
  268.                 DTranslate = trans;
  269. #ifdef g1emmx
  270.                 if((sname = resolve_a(icsource, FALSE)) != NULLCHAR) {
  271.                     tprintf(" %s", sname);
  272.                     free(sname);
  273.                 }
  274. #else
  275.                 if(ilookup){
  276.                     for(rrlp = save_rrlp = inverse_a(icsource);
  277.                         rrlp != NULLRR;
  278.                         rrlp = rrlp->next){
  279.                         if(rrlp->rdlength > 0){
  280.                             switch(rrlp->type){
  281.                             case TYPE_PTR:
  282.                                 tprintf(" %s", rrlp->rdata.name);
  283.                                 break;
  284.                             case TYPE_A:
  285.                                 tprintf(" %s", rrlp->name);
  286.                                 break;
  287.                             }
  288.                             if(rrlp->next != NULLRR)
  289.                                 tprintf("\n%20s"," ");
  290.                         }
  291.                     }
  292.                     free_rr(save_rrlp);
  293. #endif
  294.                 }
  295.                 lastaddr = icsource;
  296.             }
  297.             tprintf(" (%ld ms)",cticks);
  298. #ifdef HOPTRACE
  299.             if (Hoptrace)
  300.                 log(sp->s,
  301.                     "(hopcheck) ICMP from %s (%ldms) %s %s",
  302.                     inet_ntoa(icsource),
  303.                     cticks,
  304.                     Icmptypes[ictype],
  305.                     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  306. #endif
  307.  
  308.             /* Check type of reply */
  309.             if (ictype == ICMP_TIME_EXCEED)
  310.                 continue;
  311.             /* Reply was: destination unreachable */
  312.             switch(iccode) {
  313.             case ICMP_PORT_UNREACH:
  314.                 ++tracedone;
  315.                 break;
  316.             case ICMP_NET_UNREACH:
  317.                 ++tracedone;
  318.                 tprintf(" !N");
  319.                 break;
  320.             case ICMP_HOST_UNREACH:
  321.                 ++tracedone;
  322.                 tprintf(" !H");
  323.                 break;
  324.             case ICMP_PROT_UNREACH:
  325.                 ++tracedone;
  326.                 tprintf(" !P");
  327.                 break;
  328.             case ICMP_FRAG_NEEDED:
  329.                 ++tracedone;
  330.                 tprintf(" !F");
  331.                 break;
  332.             case ICMP_ROUTE_FAIL:
  333.                 ++tracedone;
  334.                 tprintf(" !S");
  335.                 break;
  336.             }
  337.         }
  338.         /* Done with this round of queries */
  339.         alarm((long)0);
  340.         tprintf("\n");
  341.         /* Check if we reached remote host this round */
  342.         if (tracedone != 0)
  343.             break;
  344.     }
  345.  
  346.     /* Done with traceroute */
  347. done:    close_s(s);
  348.     sp->s = -1;
  349.     close_s(s1);
  350.     tprintf("traceroute done: ");
  351.     if (sndttl >= Hopmaxttl) {
  352.         tprintf("!! maximum TTL exceeded\n");
  353.     } else if ((icsource == rsocket.address)
  354.             &&(iccode == ICMP_PORT_UNREACH)) {
  355.         tprintf("normal (%s %s)\n",
  356.             Icmptypes[ictype],Unreach[iccode]);
  357.     } else {
  358.         tprintf("!! %s %s\n",
  359.             Icmptypes[ictype],Unreach[iccode]);
  360.     }
  361. #ifdef HOPTRACE
  362.     if (Hoptrace)
  363.         log(sp->s,"HOPCHECK to %s done",sp->name);
  364. #endif
  365.     keywait(NULLCHAR,1);
  366.     freesession(sp);
  367.     return 0;
  368. }
  369.  
  370. /* Read raw network socket looking for ICMP messages in response to our
  371.  * UDP probes
  372.  */
  373. static int
  374. geticmp(s,lport,fport,sender,type,code)
  375. int s;
  376. int16 lport;
  377. int16 fport;
  378. int32 *sender;
  379. char *type,*code;
  380. {
  381.     int size;
  382.     struct icmp icmphdr;
  383.     struct ip iphdr;
  384.     struct udp udphdr;
  385.     struct mbuf *bp;
  386.     struct sockaddr_in sock;
  387.  
  388.     for(;;){
  389.         size = sizeof(sock);
  390.         if(recv_mbuf(s,&bp,0,(char *)&sock,&size) == -1)
  391.             return -1;
  392.         /* It's an ICMP message, let's see if it's interesting */
  393.         ntohicmp(&icmphdr,&bp);
  394.         if((icmphdr.type != ICMP_TIME_EXCEED ||
  395.          icmphdr.code != ICMP_TTL_EXCEED)
  396.          && icmphdr.type != ICMP_DEST_UNREACH){
  397.             /* We're not interested in these */
  398.             free_p(bp);
  399.             continue;
  400.         }
  401.         ntohip(&iphdr,&bp);
  402.         if(iphdr.protocol != UDP_PTCL){
  403.             /* Not UDP, so can't be interesting */
  404.             free_p(bp);
  405.             continue;
  406.         }
  407.         ntohudp(&udphdr,&bp);
  408.         if(udphdr.dest != fport || udphdr.source != lport){
  409.             /* Not from our hopcheck session */
  410.             free_p(bp);
  411.             continue;
  412.         }
  413.         /* Passed all of our checks, so return it */
  414.         *sender = sock.sin_addr.s_addr;
  415.         *type = icmphdr.type;
  416.         *code = icmphdr.code;
  417.         free_p(bp);
  418.         return 0;
  419.     }
  420. }
  421.